﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Timers;
//using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Reflection;
using System.Xml;
using System.Management;
using Microsoft.Win32;
using System.Threading;
using System.Security.Permissions;
using ApplicationList;

[assembly: RegistryPermissionAttribute(SecurityAction.RequestMinimum,
Read = @"HKEY_Local_Machine")]
[assembly: SecurityPermissionAttribute(SecurityAction.RequestMinimum,
    UnmanagedCode = true)]

namespace AppScan
{
    public class registry
    {
        const uint LOCAL_MACHINE = 0x80000002;
        const uint CLASSES_ROOT = 0x80000000;
        const uint CURRENT_USER = 0x80000001;
        const uint USERS = 0x80000003;
        const uint CURRENT_CONFIG = 0x80000005;
        const uint DYN_DATA = 0x80000006;
        RegistryKey environmentKey;
        string remoteName = string.Empty;

        public List<reglist> do_regread(string MACHINENAME, string REGKEY)
        {

            List<reglist> r1 = new List<reglist>();
            try
            {
                //string regs = String.Empty;
                RegistryKey regKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, MACHINENAME);
                regKey = regKey.OpenSubKey(REGKEY);
                string[] names = regKey.GetSubKeyNames();
                foreach (string entry in names)
                {
                    reglist resultItem = new reglist();
                    //MessageBox.Show(entry.ToString());
                    System.Diagnostics.Debug.WriteLine(entry.ToString());
                    //string[] arrow = do_regread(MACHINENAME, REGKEY + "\\" + entry);
                    Type t = resultItem.GetType();
                    foreach (PropertyInfo p in t.GetProperties())
                    {
                        //foreach (string value in regKey.OpenSubKey(entry).GetValueNames())
                        //{
                        try
                        {
                            p.SetValue(resultItem, this.FixString(regKey.OpenSubKey(entry).GetValue(p.Name).ToString()), null);
                        }
                        catch
                        {
                            //probably doesn't have this property
                        }
                        //System.Diagnostics.Debug.WriteLine(value + " " + regKey.OpenSubKey(entry).GetValue(value).ToString());
                        //}

                    }
                    if (resultItem.DisplayName.Length > 0)
                    {
                        //if it doesn't have a Display Name, then it probabaly is bogus
                        r1.Add(resultItem);
                    }
                }
                regKey.Close();
                return r1;
            }
            catch
            {

            }
            return r1;
        }
        //private void sort_values()
        //{
        //    reglist resultItem = new reglist();
        //    try
        //    {
        //        Type t = resultItem.GetType();

        //        foreach (PropertyInfo p in t.GetProperties())
        //        {
        //            //p.GetValue(temp[i].appitemz[k], null).ToString()
        //            if (p.PropertyType == typeof(int))
        //            {
        //                try
        //                {
        //                    if (p.Name.ToString().ToLower().Contains("number"))
        //                    {
        //                        System.Diagnostics.Debug.WriteLine(p.Name);
        //                    }
        //                    int att = System.Convert.ToInt32(this.FixString(baseObject.Properties[p.Name].Value), null);
        //                    p.SetValue(resultItem, att, null);
        //                }
        //                catch
        //                {

        //                }
        //            }
        //            else
        //            {

        //                try
        //                {
        //                    p.SetValue(resultItem, this.FixString(baseObject.Properties[p.Name].Value.ToString()), null);
        //                }
        //                catch
        //                {

        //                }
        //            }

        //        }
        //    }
        //    catch (Exception e1)
        //    {
        //        if (e1.Message.ToLower().Contains("not found"))
        //        {

        //        }
        //    }


        //}
        /// <summary>
        /// Converts values to strings, null values are returned as empty strings
        /// </summary>
        /// <param name="data">The object to convert</param>
        /// <returns>Returns a string version of the object value</returns>
        private string FixString(object data)
        {
            string resultValue = string.Empty;

            if (data != null)
            {
                resultValue = Convert.ToString(data);
            }

            return resultValue;
        }

        /// <summary>
        /// Converts a string value to an integer value
        /// </summary>
        /// <param name="data">The string value to convert to int</param>
        /// <returns>Returns integer value of string, 0 if invalid</returns>
        private int FixInteger(string data)
        {
            int resultValue = 0;

            if (data != null)
            {
                int.TryParse(data, out resultValue);
            }

            return resultValue;
        }

        private void alt_reg_read()
        {
            try
            {
                // Open HKEY_CURRENT_USER\Environment 
                // on a remote computer.
                environmentKey = RegistryKey.OpenRemoteBaseKey(
                    RegistryHive.CurrentUser, remoteName).OpenSubKey(
                    "Environment");
            }
            catch (IOException e)
            {
                Console.WriteLine("{0}: {1}",
                    e.GetType().Name, e.Message);
                return;
            }

            // Print the values.
            Console.WriteLine("\nThere are {0} values for {1}.",
                environmentKey.ValueCount.ToString(),
                environmentKey.Name);
            foreach (string valueName in environmentKey.GetValueNames())
            {
                Console.WriteLine("{0,-20}: {1}", valueName,
                    environmentKey.GetValue(valueName).ToString());
            }

            // Close the registry key.
            environmentKey.Close();
        }

        public List<reglist> WMI_readreg(string remoteHostName, string userName, string password, string key)
        {
            List<reglist> r1 = new List<reglist>();

            ManagementScope ms = null;
            ConnectionOptions wmiServiceOptions = new ConnectionOptions();
            wmiServiceOptions.Impersonation = ImpersonationLevel.Impersonate;
            wmiServiceOptions.Authentication = AuthenticationLevel.PacketPrivacy;

            string connectionString = string.Format("\\\\{0}\\root\\default", remoteHostName);
            try
            {
                if (remoteHostName != "." && remoteHostName != "localhost" && userName != "$using current credentials")
                {

                    wmiServiceOptions.Username = userName;
                    wmiServiceOptions.Password = password;
                    ms = new ManagementScope(connectionString, wmiServiceOptions);
                }
                else
                {
                    ms = new ManagementScope(connectionString, wmiServiceOptions);
                }

                ManagementClass registry = new ManagementClass(ms, new ManagementPath("StdRegProv"), null);
                //ManagementBaseObject inParams=
                //ManagementBaseObject inParams = registry.GetMethodParameters("GetStringValue");
                ManagementBaseObject inParams = registry.GetMethodParameters("EnumKey");
                Console.WriteLine("Returning a specific value for a specified key is done");
                inParams.SetPropertyValue("hDefKey", LOCAL_MACHINE);
                inParams.SetPropertyValue("sSubKeyName", key);

                //inParams["hDefKey"] = LOCAL_MACHINE;
                //inParams["sSubKeyName"] = key;

                string[] error = (string[])registry.InvokeMethod("EnumKey", inParams, null).Properties["sNames"].Value;


                foreach (string k in error)
                {
                    try
                    {
                        reglist resultItem = new reglist();
                        inParams = registry.GetMethodParameters("EnumValues");
                        inParams.SetPropertyValue("hDefKey", LOCAL_MACHINE);
                        inParams.SetPropertyValue("sSubKeyName", key + "\\" + k);

                        Type t = resultItem.GetType();
                        string[] information = (string[])registry.InvokeMethod("EnumValues", inParams, null).Properties["sNames"].Value;
                        //string[] types = (string[])registry.InvokeMethod("EnumValues", inParams, null).Properties["Types"].Value;
                        foreach (PropertyInfo p in t.GetProperties())
                        {
                            for (int i = 0; i < information.Length; i++)
                            {
                                if (p.Name == information[i])
                                {
                                    inParams = registry.GetMethodParameters("GetStringValue");
                                    inParams.SetPropertyValue("hDefKey", LOCAL_MACHINE);
                                    inParams.SetPropertyValue("sSubKeyName", key + "\\" + k);
                                    inParams.SetPropertyValue("sValueName", p.Name);
                                    try
                                    {
                                        p.SetValue(resultItem, this.FixString(registry.InvokeMethod("GetStringValue", inParams, null).Properties["sValue"].Value), null);
                                    }
                                    catch
                                    {

                                    }
                                    break;
                                }
                            }


                            ////foreach (string value in regKey.OpenSubKey(entry).GetValueNames())
                            ////{
                            //try
                            //{
                            //    p.SetValue(resultItem, this.FixString(regKey.OpenSubKey(entry).GetValue(p.Name).ToString()), null);
                            //}
                            //catch
                            //{
                            //    //probably doesn't have this property
                            //}
                            ////System.Diagnostics.Debug.WriteLine(value + " " + regKey.OpenSubKey(entry).GetValue(value).ToString());
                            ////}

                        }
                        if (resultItem.DisplayName.Length > 0)
                            r1.Add(resultItem);
                    }
                    catch
                    {

                    }
                }
                ////inParams["sValueName"] = keyToRead;
                //Console.WriteLine("Invoking Method");
                ////object[] args;
                //ManagementBaseObject outParams = registry.InvokeMethod("EnumKey", inParams, null);
                //Console.WriteLine("Invoking Method");

                //Console.WriteLine(outParams["sValue"].ToString());
                //error[0] = outParams["sValue"].ToString();
            }
            catch (Exception ex)
            {

            }
            return r1;
        }

        public List<reglist> WMI_REG(string remoteHostName, string userName, string password, string basekey, string key, List<reglist> r1)
        {
            //List<reglist> r1 = new List<reglist>();

            ManagementScope ms = null;
            ConnectionOptions wmiServiceOptions = new ConnectionOptions();
            wmiServiceOptions.Impersonation = ImpersonationLevel.Impersonate;
            wmiServiceOptions.Authentication = AuthenticationLevel.PacketPrivacy;

            string connectionString = string.Format("\\\\{0}\\root\\default", remoteHostName);
            try
            {
                if (remoteHostName != "." && remoteHostName != "localhost" && userName != "$using current credentials")
                {

                    wmiServiceOptions.Username = userName;
                    wmiServiceOptions.Password = password;
                    ms = new ManagementScope(connectionString, wmiServiceOptions);
                }
                else
                {
                    ms = new ManagementScope(connectionString, wmiServiceOptions);
                }

                ManagementClass registry = new ManagementClass(ms, new ManagementPath("StdRegProv"), null);
                //ManagementBaseObject inParams=
                //ManagementBaseObject inParams = registry.GetMethodParameters("GetStringValue");
                ManagementBaseObject inParams = registry.GetMethodParameters("EnumKey");
                Console.WriteLine("Returning a specific value for a specified key is done");
                uint HKEY = new uint();
                if (basekey == "HKLM")
                    HKEY = LOCAL_MACHINE;  
                if (basekey == "HKCU")
                    HKEY = CURRENT_USER;

                inParams.SetPropertyValue("hDefKey", HKEY);
                inParams.SetPropertyValue("sSubKeyName", key);

                //inParams["hDefKey"] = LOCAL_MACHINE;
                //inParams["sSubKeyName"] = key;

                string[] error = (string[])registry.InvokeMethod("EnumKey", inParams, null).Properties["sNames"].Value;


                foreach (string k in error)
                {
                    try
                    {
                        if (key.Contains("Installer\\UserData\\"))
                        {
                            reglist resultItem = new reglist();
                            inParams = registry.GetMethodParameters("EnumValues");
                            inParams.SetPropertyValue("hDefKey", LOCAL_MACHINE);
                            inParams.SetPropertyValue("sSubKeyName", key + "\\" + k + "\\InstallProperties");

                            Type t = resultItem.GetType();
                            string[] information = (string[])registry.InvokeMethod("EnumValues", inParams, null).Properties["sNames"].Value;
                            //string[] types = (string[])registry.InvokeMethod("EnumValues", inParams, null).Properties["Types"].Value;
                            foreach (PropertyInfo p in t.GetProperties())
                            {
                                for (int i = 0; i < information.Length; i++)
                                {
                                    if (p.Name == information[i])
                                    {
                                        inParams = registry.GetMethodParameters("GetStringValue");
                                        inParams.SetPropertyValue("hDefKey", LOCAL_MACHINE);
                                        inParams.SetPropertyValue("sSubKeyName", key + "\\" + k +"\\InstallProperties");
                                        inParams.SetPropertyValue("sValueName", p.Name);
                                        try
                                        {
                                            p.SetValue(resultItem, this.FixString(registry.InvokeMethod("GetStringValue", inParams, null).Properties["sValue"].Value), null);
                                        }
                                        catch
                                        {

                                        }
                                        break;
                                    }
                                }
                            }
                            if (resultItem.DisplayName.Length > 0)
                                r1.Add(resultItem);
                        }
                    }
                    catch
                    {

                    }
                }
                ////inParams["sValueName"] = keyToRead;
                //Console.WriteLine("Invoking Method");
                ////object[] args;
                //ManagementBaseObject outParams = registry.InvokeMethod("EnumKey", inParams, null);
                //Console.WriteLine("Invoking Method");

                //Console.WriteLine(outParams["sValue"].ToString());
                //error[0] = outParams["sValue"].ToString();
            }
            catch (Exception ex)
            {

            }

            //we need to set the display version first
            //ParseInt() on displayname, if 
            var newList = r1.OrderBy(x => x.DisplayName).ToList();
            try
            {
                for (int i = 0; i < newList.Count - 1; i++)
                {
                    //set display version first if no display version info exists
                    if (String.IsNullOrEmpty(newList[i].DisplayVersion))
                    {
                        if (!(String.IsNullOrEmpty(newList[i].VersionMajor)))
                        {
                            if (!(String.IsNullOrEmpty(newList[i].VersionMinor)))
                            {
                                newList[i].DisplayVersion = newList[i].VersionMajor + "." + newList[i].VersionMinor;
                            }
                            else
                                newList[i].DisplayVersion = newList[i].VersionMajor + ".0";
                        }
                        else
                        {
                            try
                            {
                                string holder = String.Empty;
                                char[] charray = newList[i].DisplayName.ToCharArray();
                                foreach (char c in charray)
                                {
                                    int number = 0;
                                    bool result = Int32.TryParse(c.ToString(), out number);
                                    if (result || c == '.')
                                    {
                                        holder += c.ToString();
                                    }


                                }
                                if (!String.IsNullOrEmpty(holder))
                                {
                                    newList[i].DisplayVersion = holder;
                                }
                                else
                                    newList[i].DisplayVersion = "unk";
                                //newList[i].DisplayVersion = Double.Parse(newList[i].DisplayName).ToString();
                            }
                            catch
                            {
                                newList[i].DisplayVersion = "unk";
                            }
                        }
                    }

                    for (int k = 1; k < newList.Count - 1; k++)
                    {
                        if (newList[i].DisplayName == newList[i + k].DisplayName)
                        {
                            if (newList[i].DisplayVersion == newList[i + k].DisplayVersion)
                            {
                                bool different = false;

                                for (int j = 0; j < newList.GetType().GetProperties().Length; j++)
                                {
                                    PropertyInfo p = newList[i].GetType().GetProperties()[j];
                                    string first = p.GetValue(newList[i], null).ToString();
                                    if (first == newList[i + k].GetType().GetProperties()[j].GetValue(newList[i + k], null).ToString())
                                    {

                                    }
                                    else
                                    {
                                        different = true;
                                        if (String.IsNullOrEmpty(newList[i].GetType().GetProperties()[j].GetValue(newList[i], null).ToString()))
                                        {
                                            newList[i].GetType().GetProperties()[j].SetValue(newList[i + k], j, null);
                                        }


                                    }
                                }
                                if (!different)
                                {
                                    //if we aren't different, we are a dupe.
                                    //remove at once

                                    newList.RemoveAt(i + k);
                                    k--;

                                }
                            }
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            catch
            {

            }
            var noDupes = newList.Distinct().ToList();
            return noDupes;
        }
    }
}
